package com.linghang.wusthelper.spider.library;

import com.linghang.wusthelper.common.URLConst;
import com.linghang.wusthelper.redis.RedisService;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.seimicrawler.xpath.JXDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author origin
 * 图书馆模拟登陆
 */
@Component
public class LibSimLogin {

    private static Logger log = LoggerFactory.getLogger(LibSimLogin.class);

    private static PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

    static {
        connectionManager.setMaxTotal(100);
    }

    private static RedisService redisService;

    @Autowired
    private void setRedisService(RedisService redisService){
        LibSimLogin.redisService = redisService;
    }

    /**
     * 模拟登陆
     * @param stuNum 学号
     * @param passwd 密码
     * @return resultMap code:0 请求失败 ，1 请求成功，2 请求成功但密码或账号错误
     */
    public static Map<String,String> login(String stuNum, String passwd){
        Map<String,String> resultMap = new HashMap<>();
        try {
            String PHPSESSID = redisService.get(stuNum+":PHPSESSID");
            //  检查缓存是否有PHPSESSID
            if (PHPSESSID != null){
                //  检查缓存中的cookie是否还有效
                if (testLogin(PHPSESSID)){
                    resultMap.put("PHPSESSID",PHPSESSID);
                    resultMap.put("code","1");
                    return resultMap;
                }else {
                    //  删除无效cookie
                    redisService.remove("PHPSESSID");
                }
            }
            Map<String,Object> map = getCode();
            resultMap = simLogin(map,stuNum,passwd);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("图书馆登陆失败:"+stuNum);
            resultMap.put("code","0");
            return resultMap;
        }
    }

    /**
     * 获取验证码
     * @return map cookie以及验证码
     * @throws IOException
     */
    private static Map<String,Object> getCode() throws IOException {

        HttpGet httpGet = new HttpGet(URLConst.LIBCODEURL);
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setSocketTimeout(5000).setConnectTimeout(5000).build();
        httpGet.setConfig(requestConfig);

        CookieStore cookieStore = new BasicCookieStore();      //  设置初始cookie
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultCookieStore(cookieStore).build();

        //  设置请求头信息
        httpGet.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        httpGet.setHeader("Accept-Encoding", "gzip,deflate,sdch");
        httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
        httpGet.setHeader("Connection", "keep-alive");
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36");

        CloseableHttpResponse httpResponse = httpClient.execute(httpGet);   //  执行请求

        HttpEntity entity = httpResponse.getEntity();
        String result = EntityUtils.toString(entity,"UTF-8");     //  获取html页面
        JXDocument jxDocument = JXDocument.create(result);
        String xpth = "//*[@id=\"csrf_token\"]/@value";
        String code = (String) jxDocument.selOne(xpth);      //  通过Xpath选择器获取验证码

        Map<String,Object> map = new HashMap();
        map.put("code",code);
        map.put("cookieStore",cookieStore);        //  将cookie存入map
        httpGet.releaseConnection();
        httpResponse.close();
        return map;
    }

    /**
     * 模拟图书馆登陆
     * @param cookieMap cookie以及验证码
     * @param stuNum 学号
     * @param passwd 密码
     * @return SESSIONID
     * @throws IOException
     */
    private static Map<String,String> simLogin(Map<String,Object> cookieMap,String stuNum,String passwd) throws IOException {

        HttpPost httpPost = new HttpPost(URLConst.LIBLOGINURL);

        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setSocketTimeout(5000).setConnectTimeout(5000).build();
        httpPost.setConfig(requestConfig);

        CookieStore cookieStore = (CookieStore) cookieMap.get("cookieStore");       //从map中获取cookie
        BasicClientCookie basicClientCookie = new BasicClientCookie("expiry","Tue, 19 Jan 2038 03:14:07 GMT");
        cookieStore.addCookie(basicClientCookie);
        //  将cookie加入请求头
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultCookieStore(cookieStore).build();

        //  设置请求头
        httpPost.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        httpPost.setHeader("Accept-Encoding", "gzip, deflate");
        httpPost.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
        httpPost.setHeader("Cache-Control","max-age=0");
        httpPost.setHeader("Content-Type","application/x-www-form-urlencoded");
        httpPost.setHeader("Host","www.lib.wust.edu.cn:8780");
        httpPost.setHeader("Origin","http://www.lib.wust.edu.cn:8780");
        httpPost.setHeader("Referer","http://www.lib.wust.edu.cn:8780/reader/redr_verify.php");
        httpPost.setHeader("Connection", "keep-alive");
        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");

        //  添加登陆参数
        List<NameValuePair> pairs = new ArrayList<>();
        pairs.add(new BasicNameValuePair("number",stuNum));   //  学号
        pairs.add(new BasicNameValuePair("passwd",passwd));   //  密码
        pairs.add(new BasicNameValuePair("select","bar_no"));   //  选择序列号登陆
        pairs.add(new BasicNameValuePair("returnUrl",""));
        pairs.add(new BasicNameValuePair("csrf_token", (String) cookieMap.get("code")));   //  验证码
        httpPost.setEntity(new UrlEncodedFormEntity(pairs,"UTF-8"));   //  添加参数

        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);  //  执行请求

        Map<String,String> resultMap = new HashMap<>();
        //  判断网络请求是否成功
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK || httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY){
            HttpEntity entity = httpResponse.getEntity();
            String result = EntityUtils.toString(entity,"UTF-8");  //获取html页面

            JXDocument jxDocument = JXDocument.create(result);
            String xpth = "//*[@id=\"fontMsg\"]/text()";
            String errorMsg = (String) jxDocument.selOne(xpth);      //  通过Xpath选择器获取错误信息

            //  判断是否登录成功
            if (errorMsg == null){
                //  获取PHPSESSID
                List<Cookie> cookies = cookieStore.getCookies();
                String PHPSESSID = "";
                for (Cookie cookie: cookies){
                    if (cookie.getName().equals("PHPSESSID")){
                        PHPSESSID += cookie.getValue();
                    }
                }

                //todo  将PHPSESSID存入缓存
                redisService.set(stuNum+":PHPSESSID",PHPSESSID,1200);
                resultMap.put("PHPSESSID",PHPSESSID);
                resultMap.put("code","1");
                httpResponse.close();
                httpPost.releaseConnection();
                return resultMap;
            }else {
                resultMap.put("errorMsg",errorMsg);
                resultMap.put("code","2");
                httpResponse.close();
                httpPost.releaseConnection();
                return resultMap;
            }
        }else {
            resultMap.put("code","0");
            httpPost.releaseConnection();
            httpResponse.close();
            return resultMap;
        }

    }

    /**
     * 测试cookies是否有效
     * @param PHPSESSID
     * @return
     * @throws IOException
     */
    private static boolean testLogin(String PHPSESSID) throws IOException {

        HttpGet httpGet = new HttpGet(URLConst.LIBTESTLOGINURL);
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setSocketTimeout(5000).setConnectTimeout(5000).build();
        httpGet.setConfig(requestConfig);

        CookieStore cookieStore = new BasicCookieStore();

        //  添加cookie
        BasicClientCookie cookie = new BasicClientCookie("PHPSESSID",PHPSESSID);
        cookie.setDomain("www.lib.wust.edu.cn");
        cookie.setPath("/");
        cookie.setVersion(0);
        cookieStore.addCookie(cookie);
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultCookieStore(cookieStore).build();

        //  设置请求头
        httpGet.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        httpGet.setHeader("Accept-Encoding", "gzip, deflate");
        httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
        httpGet.setHeader("Cache-Control","max-age=0");
        httpGet.setHeader("Content-Type","application/x-www-form-urlencoded");
        httpGet.setHeader("Host","www.lib.wust.edu.cn:8780");
        httpGet.setHeader("Origin","http://www.lib.wust.edu.cn:8780");
        httpGet.setHeader("Referer","http://www.lib.wust.edu.cn:8780/reader/redr_verify.php");
        httpGet.setHeader("Connection", "keep-alive");
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");

        CloseableHttpResponse httpResponse = httpClient.execute(httpGet);  //  执行请求

        HttpEntity entity = httpResponse.getEntity();
        String result = EntityUtils.toString(entity,"UTF-8");     //  获取html页面

        JXDocument jxDocument = JXDocument.create(result);
        String xpth = "//*[@id=\"left_tab\"]/h5/strong/text()";
        String test = (String) jxDocument.selOne(xpth);      //  通过Xpath选择器获取验证码
        httpGet.releaseConnection();
        httpResponse.close();

        if (test != null && test.equals("登录我的图书馆")){
            return false;
        }else {
            return true;
        }
    }
}
